/**
 * MySQL EXPLAIN 可视化器
 * 使用 AntV G6 4.x 进行图形渲染
 */
class ExplainVisualizer {
    constructor(containerId) {
        this.containerId = containerId;
        this.graph = null;
        this.data = null;
        this.currentZoom = 1;
        this.lockedLegends = {
            nodeType: null,  // 锁定的节点类型
            special: null    // 锁定的特殊类型 (warning 或 high-cost)
        };
    }

    /**
     * 初始化图形
     */
    init() {
        const container = document.getElementById(this.containerId);
        if (!container) {
            throw new Error(`Container ${this.containerId} not found`);
        }

        // 获取容器尺寸
        const { clientWidth, clientHeight } = container;

        // 创建G6图实例
        this.graph = new G6.TreeGraph({
            container: this.containerId,
            width: clientWidth,
            height: clientHeight,
            modes: {
                default: [
                    'drag-canvas',
                    'zoom-canvas',
                    'drag-node'
                ]
            },
            layout: {
                type: 'compactBox',
                direction: 'TB', // 从上到下
                getId: function getId(d) {
                    return d.id;
                },
                getHeight: function getHeight() {
                    return 120;
                },
                getWidth: function getWidth() {
                    return 240;
                },
                getVGap: function getVGap() {
                    return 60;
                },
                getHGap: function getHGap() {
                    return 80;
                }
            },
            defaultNode: {
                type: 'rect',
                size: [240, 120],
                // 配置锚点：上方、下方、左侧、右侧
                anchorPoints: [
                    [0.5, 0],    // 上方中心
                    [0.5, 1],    // 下方中心
                    [0, 0.5],    // 左侧中心
                    [1, 0.5]     // 右侧中心
                ],
                style: {
                    radius: 12,
                    stroke: '#1890ff',
                    lineWidth: 3,
                    fill: 'l(270) 0:#ffffff 0.5:#f8fbff 1:#e6f7ff',
                    shadowColor: 'rgba(24, 144, 255, 0.3)',
                    shadowBlur: 20,
                    shadowOffsetX: 0,
                    shadowOffsetY: 8,
                    cursor: 'pointer'
                },
                labelCfg: {
                    style: {
                        fontSize: 13,
                        fontWeight: '600',
                        textAlign: 'center',
                        textBaseline: 'middle',
                        fill: '#2c3e50',
                        fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
                    }
                }
            },
            defaultEdge: {
                type: 'cubic-vertical',
                // 配置连线锚点：从源节点下方连到目标节点上方
                sourceAnchor: 1,  // 使用下方锚点 (index 1: [0.5, 1])
                targetAnchor: 0,  // 使用上方锚点 (index 0: [0.5, 0])
                style: {
                    stroke: 'l(0) 0:#91d5ff 1:#1890ff',
                    lineWidth: 3,
                    endArrow: {
                        path: 'M 0,0 L 8,4 L 8,-4 Z',
                        fill: '#1890ff',
                        stroke: '#1890ff'
                    },
                    shadowColor: 'rgba(24, 144, 255, 0.2)',
                    shadowBlur: 6,
                    opacity: 0.8
                }
            },
            nodeStateStyles: {
                hover: {
                    stroke: '#40a9ff',
                    lineWidth: 4,
                    shadowColor: 'rgba(64, 169, 255, 0.5)',
                    shadowBlur: 25,
                    shadowOffsetY: 12,
                    fill: 'l(270) 0:#ffffff 0.3:#f0f9ff 1:#e6f7ff',
                    cursor: 'pointer'
                },
                selected: {
                    stroke: '#1890ff',
                    lineWidth: 4,
                    fill: 'l(270) 0:#e6f7ff 0.5:#bae7ff 1:#91d5ff',
                    shadowColor: 'rgba(24, 144, 255, 0.6)',
                    shadowBlur: 30,
                    shadowOffsetY: 15
                }
            },
            // 为特殊节点类型添加自定义状态样式
            customStateStyles: {
                warning: {
                    hover: {
                        stroke: '#ff7875',
                        lineWidth: 4,
                        shadowColor: 'rgba(255, 77, 79, 0.5)',
                        shadowBlur: 25,
                        shadowOffsetY: 12,
                        fill: 'l(270) 0:#fff2f0 0.3:#ffccc7 1:#ffa39e',
                        cursor: 'pointer'
                    },
                    select: {
                        stroke: '#f5222d',
                        lineWidth: 5,
                        shadowColor: 'rgba(255, 77, 79, 0.6)',
                        shadowBlur: 30,
                        shadowOffsetY: 15,
                        fill: 'l(270) 0:#fff1f0 0.5:#ffa39e 1:#ff7875',
                        cursor: 'pointer'
                    }
                },
                highCost: {
                    hover: {
                        stroke: '#ffa940',
                        lineWidth: 4,
                        shadowColor: 'rgba(250, 140, 22, 0.5)',
                        shadowBlur: 25,
                        shadowOffsetY: 12,
                        fill: 'l(270) 0:#fff7e6 0.3:#ffe7ba 1:#ffd591',
                        cursor: 'pointer'
                    },
                    select: {
                        stroke: '#fa8c16',
                        lineWidth: 5,
                        shadowColor: 'rgba(250, 140, 22, 0.6)',
                        shadowBlur: 30,
                        shadowOffsetY: 15,
                        fill: 'l(270) 0:#fff7e6 0.5:#ffd591 1:#ffa940',
                        cursor: 'pointer'
                    }
                }
            }
        });

        // 绑定事件
        this.bindEvents();

        // 监听窗口大小变化
        window.addEventListener('resize', () => this.handleResize());
    }

    /**
     * 绑定图形事件
     */
    bindEvents() {
        // 当前选中的节点
        this.selectedNode = null;

        // 节点点击事件
        this.graph.on('node:click', (e) => {
            const { item } = e;
            const model = item.getModel();
            
            // 显示节点详情
            this.showNodeDetails(model);
            
            // 处理节点选中逻辑
            this.handleNodeSelection(item);
        });

        // 节点悬停事件
        this.graph.on('node:mouseenter', (e) => {
            const { item } = e;
            const model = item.getModel();
            
            // 如果节点已经被选中，则不应用悬停样式
            if (this.selectedNode === item) {
                return;
            }
            
            // 根据节点类型应用不同的悬停样式
            if (model.originalData && model.originalData.warnings && model.originalData.warnings.length > 0) {
                // 警告节点使用自定义警告样式
                this.applyCustomHoverStyle(item, 'warning');
            } else if (model.originalData && model.originalData.performance_metrics && model.originalData.performance_metrics.cost > 100) {
                // 高成本节点使用自定义高成本样式
                this.applyCustomHoverStyle(item, 'highCost');
            } else {
                // 普通节点使用默认悬停样式
                this.graph.setItemState(item, 'hover', true);
            }
        });

        this.graph.on('node:mouseleave', (e) => {
            const { item } = e;
            
            // 如果节点已经被选中，则不清除样式
            if (this.selectedNode === item) {
                return;
            }
            
            // 清除所有可能的状态
            this.graph.setItemState(item, 'hover', false);
            this.clearCustomHoverStyles(item);
        });

        // 画布点击事件（隐藏详情面板，但不取消节点选中状态）
        this.graph.on('canvas:click', () => {
            this.hideNodeDetails();
        });
    }
    
    /**
     * 处理节点选中逻辑
     */
    handleNodeSelection(item) {
        if (!item) return;
        
        // 如果点击的是当前已选中的节点，则取消选中
        if (this.selectedNode === item) {
            this.clearNodeSelection();
            return;
        }
        
        // 如果之前有选中的节点，先清除它的选中状态
        if (this.selectedNode) {
            this.clearNodeSelection();
        }
        
        // 设置新的选中节点
        this.selectedNode = item;
        const model = item.getModel();
        
        // 根据节点类型应用不同的选中样式
        if (model.originalData && model.originalData.warnings && model.originalData.warnings.length > 0) {
            // 警告节点使用自定义警告样式
            this.applyCustomSelectStyle(item, 'warning');
        } else if (model.originalData && model.originalData.performance_metrics && model.originalData.performance_metrics.cost > 100) {
            // 高成本节点使用自定义高成本样式
            this.applyCustomSelectStyle(item, 'highCost');
        } else {
            // 普通节点使用默认选中样式
            this.graph.setItemState(item, 'selected', true);
        }
    }
    
    /**
     * 清除节点选中状态
     */
    clearNodeSelection() {
        if (!this.selectedNode) return;
        
        // 清除选中状态
        this.graph.setItemState(this.selectedNode, 'selected', false);
        this.clearCustomSelectStyles(this.selectedNode);
        
        // 重置选中节点
        this.selectedNode = null;
    }
    
    /**
     * 应用自定义悬停样式
     */
    applyCustomHoverStyle(item, styleType) {
        if (!this.graph || !item) return;
        
        const customStyle = this.graph.get('customStateStyles')[styleType].hover;
        if (!customStyle) return;
        
        const keyShape = item.getKeyShape();
        if (!keyShape) return;
        
        // 保存原始样式以便恢复
        if (!item._originStyle) {
            const style = {};
            Object.keys(customStyle).forEach(key => {
                style[key] = keyShape.attr(key);
            });
            item._originStyle = style;
        }
        
        // 应用自定义样式
        keyShape.attr(customStyle);
    }
    
    /**
     * 清除自定义悬停样式
     */
    clearCustomHoverStyles(item) {
        if (!item || !item._originStyle) return;
        
        const keyShape = item.getKeyShape();
        if (!keyShape) return;
        
        // 恢复原始样式
        keyShape.attr(item._originStyle);
        delete item._originStyle;
    }
    
    /**
     * 应用自定义选中样式
     */
    applyCustomSelectStyle(item, styleType) {
        if (!this.graph || !item) return;
        
        // 获取自定义选中样式
        const customStyle = this.graph.get('customStateStyles')[styleType].select || this.graph.get('customStateStyles')[styleType].hover;
        if (!customStyle) return;
        
        const keyShape = item.getKeyShape();
        if (!keyShape) return;
        
        // 保存原始样式以便恢复
        if (!item._originSelectStyle) {
            const style = {};
            Object.keys(customStyle).forEach(key => {
                style[key] = keyShape.attr(key);
            });
            item._originSelectStyle = style;
        }
        
        // 应用自定义选中样式
        keyShape.attr({
            ...customStyle,
            // 增强选中效果
            lineWidth: (customStyle.lineWidth || 3) + 1,
            shadowBlur: (customStyle.shadowBlur || 20) + 10,
            shadowOffsetY: (customStyle.shadowOffsetY || 8) + 2
        });
    }
    
    /**
     * 清除自定义选中样式
     */
    clearCustomSelectStyles(item) {
        if (!item || !item._originSelectStyle) return;
        
        const keyShape = item.getKeyShape();
        if (!keyShape) return;
        
        // 恢复原始样式
        keyShape.attr(item._originSelectStyle);
        delete item._originSelectStyle;
    }

    /**
     * 渲染执行计划
     */
    render(parseResult) {
        if (!this.graph) {
            this.init();
        }

        // 重置锁定的图例状态
        this.lockedLegends = {
            nodeType: null,
            special: null
        };

        this.data = parseResult;
        
        // 转换数据格式
        const graphData = this.convertToGraphData(parseResult.root);
        
        // 渲染图形
        this.graph.data(graphData);
        this.graph.render();
        
        // 适应画布
        this.graph.fitView();
        
        // 添加进入动画
        this.addEnterAnimation();
        
        // 更新统计信息
        this.updateStats(parseResult.stats);
    }

    /**
     * 转换数据为G6格式
     */
    convertToGraphData(root) {
        if (!root) return null;

        const convertNode = (node) => {
            const graphNode = {
                id: node.id,
                label: this.formatNodeLabel(node),
                ...this.getNodeStyle(node),
                originalData: node
            };

            if (node.children && node.children.length > 0) {
                graphNode.children = node.children.map(child => convertNode(child));
            }

            return graphNode;
        };

        return convertNode(root);
    }

    /**
     * 格式化节点标签
     */
    formatNodeLabel(node) {
        const lines = [];
        const colors = this.getNodeColors(node.node_type);
        
        // 图标和主标签
        lines.push(`${colors.icon} ${this.truncateText(node.label, 22)}`);
        
        // 空行分隔
        lines.push('');
        
        // 性能指标 - 更紧凑的显示
        const metrics = [];
        if (node.performance_metrics.cost > 0) {
            metrics.push(`💰 ${node.performance_metrics.cost.toFixed(1)}`);
        }
        if (node.performance_metrics.rows > 0) {
            metrics.push(`📊 ${this.formatNumber(node.performance_metrics.rows)}`);
        }
        
        if (metrics.length > 0) {
            lines.push(metrics.join('  '));
        }

        // 索引信息
        if (node.index_info.key) {
            lines.push(`🔑 ${this.truncateText(node.index_info.key, 18)}`);
        }

        // 警告标识
        if (node.warnings && node.warnings.length > 0) {
            lines.push('⚠️ 性能警告');
        }

        return lines.join('\n');
    }

    /**
     * 获取节点样式
     */
    getNodeStyle(node) {
        const style = {
            type: 'rect',
            size: [240, 120],
            // 确保每个节点都有锚点配置
            anchorPoints: [
                [0.5, 0],    // 上方中心
                [0.5, 1],    // 下方中心
                [0, 0.5],    // 左侧中心
                [1, 0.5]     // 右侧中心
            ]
        };

        // 根据节点类型设置颜色
        const colors = this.getNodeColors(node.node_type);
        style.style = {
            radius: 12,
            lineWidth: 3,
            shadowBlur: 20,
            shadowOffsetX: 0,
            shadowOffsetY: 8,
            cursor: 'pointer',
            fill: colors.fill,
            stroke: colors.stroke,
            shadowColor: colors.shadowColor
        };

        // 根据性能指标调整样式
        if (node.warnings && node.warnings.length > 0) {
            style.style.stroke = '#ff4d4f';
            style.style.fill = 'l(270) 0:#fff2f0 0.5:#ffe7e7 1:#ffd6d6';
            style.style.shadowColor = 'rgba(255, 77, 79, 0.3)';
        }

        // 高成本节点
        if (node.performance_metrics.cost > 100) {
            style.style.stroke = '#fa8c16';
            style.style.fill = 'l(270) 0:#fff7e6 0.5:#ffe7ba 1:#ffd666';
            style.style.shadowColor = 'rgba(250, 140, 22, 0.3)';
        }

        return style;
    }

    /**
     * 获取节点类型对应的颜色和图标
     */
    getNodeColors(nodeType) {
        const colorMap = {
            'sort': { 
                fill: 'l(270) 0:#f6ffed 0.5:#eaffde 1:#d9f7be', 
                stroke: '#52c41a',
                shadowColor: 'rgba(82, 196, 26, 0.3)',
                icon: '↕️'
            },
            'nested_loop_join': { 
                fill: 'l(270) 0:#e6f7ff 0.5:#bae7ff 1:#91d5ff', 
                stroke: '#1890ff',
                shadowColor: 'rgba(24, 144, 255, 0.3)',
                icon: '🔗'
            },
            'hash_join': { 
                fill: 'l(270) 0:#f9f0ff 0.5:#efdbff 1:#d3adf7', 
                stroke: '#722ed1',
                shadowColor: 'rgba(114, 46, 209, 0.3)',
                icon: '#️⃣'
            },
            'index_scan': { 
                fill: 'l(270) 0:#e6fffb 0.5:#b5f5ec 1:#87e8de', 
                stroke: '#13c2c2',
                shadowColor: 'rgba(19, 194, 194, 0.3)',
                icon: '📇'
            },
            'index_lookup': { 
                fill: 'l(270) 0:#e6fffb 0.5:#b5f5ec 1:#87e8de', 
                stroke: '#08979c',
                shadowColor: 'rgba(8, 151, 156, 0.3)',
                icon: '🔍'
            },
            'filter': { 
                fill: 'l(270) 0:#fff2e8 0.5:#ffd8bf 1:#ffbb96', 
                stroke: '#fa8c16',
                shadowColor: 'rgba(250, 140, 22, 0.3)',
                icon: '🔽'
            },
            'table_scan': { 
                fill: 'l(270) 0:#fff1f0 0.5:#ffa39e 1:#ff7875', 
                stroke: '#f5222d',
                shadowColor: 'rgba(245, 34, 45, 0.3)',
                icon: '📊'
            },
            'aggregate': { 
                fill: 'l(270) 0:#f0f9ff 0.5:#85a5ff 1:#597ef7', 
                stroke: '#2f54eb',
                shadowColor: 'rgba(47, 84, 235, 0.3)',
                icon: '📈'
            },
            'group_by': { 
                fill: 'l(270) 0:#f0f9ff 0.5:#85a5ff 1:#597ef7', 
                stroke: '#1d39c4',
                shadowColor: 'rgba(29, 57, 196, 0.3)',
                icon: '📋'
            },
            'subquery': { 
                fill: 'l(270) 0:#fef0ff 0.5:#ffc2db 1:#ff85c0', 
                stroke: '#eb2f96',
                shadowColor: 'rgba(235, 47, 150, 0.3)',
                icon: '🔄'
            },
            'materialize': { 
                fill: 'l(270) 0:#fcffe6 0.5:#eaff8f 1:#d3f261', 
                stroke: '#a0d911',
                shadowColor: 'rgba(160, 217, 17, 0.3)',
                icon: '💾'
            },
            'window_function': { 
                fill: 'l(270) 0:#e6f4ff 0.5:#adc6ff 1:#85a5ff', 
                stroke: '#597ef7',
                shadowColor: 'rgba(89, 126, 247, 0.3)',
                icon: '🪟'
            },
            'query_block': {
                fill: 'l(270) 0:#f0f0f0 0.5:#d9d9d9 1:#bfbfbf',
                stroke: '#8c8c8c',
                shadowColor: 'rgba(140, 140, 140, 0.3)',
                icon: '📦'
            },
            'default': { 
                fill: 'l(270) 0:#ffffff 0.5:#f5f5f5 1:#e8e8e8', 
                stroke: '#d9d9d9',
                shadowColor: 'rgba(217, 217, 217, 0.3)',
                icon: '⚙️'
            }
        };

        return colorMap[nodeType] || colorMap['default'];
    }

    /**
     * 截断文本
     */
    truncateText(text, maxLength) {
        if (text.length <= maxLength) return text;
        return text.substring(0, maxLength - 3) + '...';
    }

    /**
     * 格式化数字
     */
    formatNumber(num) {
        if (num >= 1000000) {
            return (num / 1000000).toFixed(1) + 'M';
        }
        if (num >= 1000) {
            return (num / 1000).toFixed(1) + 'K';
        }
        return num.toString();
    }

    /**
     * 显示节点详情
     */
    showNodeDetails(nodeModel) {
        const detailsPanel = document.getElementById('nodeDetails');
        const detailsContent = document.getElementById('detailsContent');
        
        if (!detailsPanel || !detailsContent) return;

        const node = nodeModel.originalData;
        
        // 获取SQL示例
        const sqlExamples = this.generateSqlExamples(node);
        
        const html = `
            <div class="detail-section">
                <h4>基本信息</h4>
                <div class="detail-item">
                    <span class="detail-label">节点类型:</span>
                    <span class="detail-value">${this.getNodeTypeDisplay(node.node_type)}</span>
                </div>
                <div class="detail-item">
                    <span class="detail-label">操作描述:</span>
                    <span class="detail-value">${node.label}</span>
                </div>
                <div class="detail-item">
                    <span class="detail-label">访问类型:</span>
                    <span class="detail-value">${node.access_type || 'N/A'}</span>
                </div>
            </div>

            <div class="detail-section">
                <h4>性能指标</h4>
                <div class="detail-item">
                    <span class="detail-label">成本:</span>
                    <span class="detail-value">${node.performance_metrics.cost.toFixed(2)}</span>
                </div>
                <div class="detail-item">
                    <span class="detail-label">行数:</span>
                    <span class="detail-value">${this.formatNumber(node.performance_metrics.rows)}</span>
                </div>
                <div class="detail-item">
                    <span class="detail-label">过滤率:</span>
                    <span class="detail-value">${node.performance_metrics.filtered.toFixed(2)}%</span>
                </div>
                ${node.performance_metrics.execution_time ? `
                <div class="detail-item">
                    <span class="detail-label">执行时间:</span>
                    <span class="detail-value">${node.performance_metrics.execution_time.toFixed(3)}ms</span>
                </div>
                ` : ''}
            </div>

            ${node.index_info.key ? `
            <div class="detail-section">
                <h4>索引信息</h4>
                <div class="detail-item">
                    <span class="detail-label">索引名:</span>
                    <span class="detail-value">${node.index_info.key}</span>
                </div>
                ${node.index_info.key_len ? `
                <div class="detail-item">
                    <span class="detail-label">索引长度:</span>
                    <span class="detail-value">${node.index_info.key_len}</span>
                </div>
                ` : ''}
            </div>
            ` : ''}

            ${node.warnings.length > 0 ? `
            <div class="detail-section">
                <h4>性能警告</h4>
                ${node.warnings.map(warning => `
                    <div class="warning-item">⚠️ ${warning}</div>
                `).join('')}
            </div>
            ` : ''}

            ${node.suggestions.length > 0 ? `
            <div class="detail-section">
                <h4>优化建议</h4>
                ${node.suggestions.map(suggestion => `
                    <div class="suggestion-item">💡 ${suggestion}</div>
                `).join('')}
            </div>
            ` : ''}

            ${sqlExamples ? `
            <div class="detail-section sql-examples-section">
                <h4>
                    📝 SQL示例 - ${sqlExamples.title}
                    <button class="sql-examples-toggle" id="sqlExamplesToggle" title="展开/收起SQL示例">
                        <span class="toggle-icon">▼</span>
                    </button>
                </h4>
                <div class="sql-examples-description">
                    ${sqlExamples.description}
                </div>
                <div class="sql-examples-content" id="sqlExamplesContent">
                    ${sqlExamples.examples.map((example, index) => `
                        <div class="sql-example-item">
                            <div class="sql-example-header">
                                <h5>${example.name}</h5>
                                <div class="sql-example-actions">
                                    <button class="copy-sql-btn" data-sql="${this.escapeHtml(example.sql)}" title="复制SQL语句">
                                        📋 复制SQL
                                    </button>
                                    <button class="copy-explain-btn" data-sql="${this.escapeHtml(example.explain_sql)}" title="复制EXPLAIN语句">
                                        🔍 复制EXPLAIN
                                    </button>
                                </div>
                            </div>
                            <div class="sql-code-block">
                                <pre><code class="sql-code">${this.highlightSQL(example.sql)}</code></pre>
                            </div>
                        </div>
                    `).join('')}
                    
                    ${this.generateOptimizationSQL(node) ? `
                    <div class="sql-example-item">
                        <div class="sql-example-header">
                            <h5>🚀 性能优化建议</h5>
                            <button class="copy-sql-btn" data-sql="${this.escapeHtml(this.generateOptimizationSQL(node))}" title="复制优化SQL">
                                📋 复制优化SQL
                            </button>
                        </div>
                        <div class="sql-code-block">
                            <pre><code class="sql-code">${this.highlightSQL(this.generateOptimizationSQL(node))}</code></pre>
                        </div>
                    </div>
                    ` : ''}
                </div>
            </div>
            ` : ''}
        `;

        detailsContent.innerHTML = html;
        
        // 绑定SQL示例相关事件
        this.bindSqlExampleEvents();
        
        detailsPanel.classList.remove('hidden');
    }

    /**
     * 隐藏节点详情
     */
    hideNodeDetails() {
        const detailsPanel = document.getElementById('nodeDetails');
        if (detailsPanel) {
            detailsPanel.classList.add('hidden');
        }
    }

    /**
     * 获取节点类型显示名称
     */
    getNodeTypeDisplay(nodeType) {
        const typeMap = {
            'sort': '排序操作',
            'nested_loop_join': '嵌套循环连接',
            'hash_join': '哈希连接',
            'index_scan': '索引扫描',
            'index_lookup': '索引查找',
            'filter': '过滤条件',
            'table_scan': '表扫描',
            'aggregate': '聚合函数',
            'group_by': '分组操作',
            'subquery': '子查询',
            'materialize': '物化操作',
            'window_function': '窗口函数',
            'query_block': '查询块'
        };
        
        return typeMap[nodeType] || nodeType;
    }

    /**
     * 更新统计信息
     */
    updateStats(stats) {
        const elements = {
            totalCost: document.getElementById('totalCost'),
            nodeCount: document.getElementById('nodeCount'),
            executionTime: document.getElementById('executionTime'),
            rowsExamined: document.getElementById('rowsExamined')
        };

        if (elements.totalCost) {
            elements.totalCost.textContent = stats.totalCost.toFixed(2);
        }
        
        if (elements.nodeCount) {
            elements.nodeCount.textContent = stats.nodeCount.toString();
        }
        
        if (elements.executionTime) {
            elements.executionTime.textContent = stats.executionTime 
                ? `${stats.executionTime.toFixed(3)}ms` 
                : '-';
        }
        
        if (elements.rowsExamined) {
            elements.rowsExamined.textContent = this.formatNumber(stats.rowsExamined);
        }

        // 创建或更新图例
        this.createLegend();
    }

    /**
     * 创建图例组件
     */
    createLegend() {
        let legendContainer = document.getElementById('nodeTypeLegend');
        
        if (!legendContainer) {
            // 创建图例容器
            legendContainer = document.createElement('div');
            legendContainer.id = 'nodeTypeLegend';
            legendContainer.className = 'floating-legend';
            
            const visualizationContainer = document.querySelector('.visualization-container');
            visualizationContainer.appendChild(legendContainer);
        }

        // 收集当前图中实际存在的节点类型
        const existingTypes = this.collectExistingNodeTypes();
        
        // 检查是否有警告和高成本节点
        const hasWarnings = this.hasWarningNodes();
        const hasHighCost = this.hasHighCostNodes();

        const legendHTML = `
            <button class="floating-legend-toggle" id="legendToggleBtn" title="显示/隐藏节点类型图例">
                🏷️
            </button>
            <div class="legend-grid" id="legendContent">
                ${existingTypes.map(type => {
                    const colors = this.getNodeColors(type);
                    const displayName = this.getNodeTypeDisplay(type);
                    return `
                        <div class="legend-chip" data-type="${type}" title="${displayName}">
                            <div class="legend-chip-icon" style="
                                background: ${colors.fill};
                                border: 1px solid ${colors.stroke};
                                box-shadow: 0 1px 4px ${colors.shadowColor};
                            ">
                                <span>${colors.icon}</span>
                            </div>
                            <span class="legend-chip-text">${displayName}</span>
                        </div>
                    `;
                }).join('')}
                
                ${hasWarnings ? `
                <div class="legend-chip warning-chip" data-special="warning" title="性能警告">
                    <div class="legend-chip-icon warning-color">
                        <span>⚠️</span>
                    </div>
                    <span class="legend-chip-text">警告</span>
                </div>
                ` : ''}
                
                ${hasHighCost ? `
                <div class="legend-chip high-cost-chip" data-special="high-cost" title="高成本操作">
                    <div class="legend-chip-icon high-cost-color">
                        <span>💰</span>
                    </div>
                    <span class="legend-chip-text">高成本</span>
                </div>
                ` : ''}
            </div>
        `;

        legendContainer.innerHTML = legendHTML;
        
        // 绑定图例切换事件
        const toggleBtn = document.getElementById('legendToggleBtn');
        if (toggleBtn) {
            toggleBtn.addEventListener('click', this.toggleLegend.bind(this));
        }

        // 绑定图例项悬停事件
        this.bindLegendEvents();
    }

    /**
     * 收集当前图中实际存在的节点类型
     */
    collectExistingNodeTypes() {
        if (!this.data || !this.data.root) {
            return [];
        }

        const types = new Set();
        
        const collectTypes = (node) => {
            if (node.node_type) {
                types.add(node.node_type);
            }
            if (node.children && node.children.length > 0) {
                node.children.forEach(child => collectTypes(child));
            }
        };

        collectTypes(this.data.root);
        return Array.from(types).sort();
    }

    /**
     * 检查是否有警告节点
     */
    hasWarningNodes() {
        if (!this.data || !this.data.root) {
            return false;
        }

        const checkWarnings = (node) => {
            if (node.warnings && node.warnings.length > 0) {
                return true;
            }
            if (node.children && node.children.length > 0) {
                return node.children.some(child => checkWarnings(child));
            }
            return false;
        };

        return checkWarnings(this.data.root);
    }

    /**
     * 检查是否有高成本节点
     */
    hasHighCostNodes() {
        if (!this.data || !this.data.root) {
            return false;
        }

        const checkHighCost = (node) => {
            if (node.performance_metrics && node.performance_metrics.cost > 100) {
                return true;
            }
            if (node.children && node.children.length > 0) {
                return node.children.some(child => checkHighCost(child));
            }
            return false;
        };

        return checkHighCost(this.data.root);
    }

    /**
     * 切换图例显示/隐藏
     */
    toggleLegend() {
        const legend = document.getElementById('nodeTypeLegend');
        const content = document.getElementById('legendContent');
        const toggleBtn = document.getElementById('legendToggleBtn');
        
        if (legend.classList.contains('collapsed')) {
            legend.classList.remove('collapsed');
            content.style.display = 'flex';
            toggleBtn.style.opacity = '1';
            toggleBtn.title = '隐藏节点类型图例';
        } else {
            legend.classList.add('collapsed');
            content.style.display = 'none';
            toggleBtn.style.opacity = '0.6';
            toggleBtn.title = '显示节点类型图例';
        }
    }

    /**
     * 绑定图例事件
     */
    bindLegendEvents() {
        const legendChips = document.querySelectorAll('.legend-chip[data-type]');
        
        legendChips.forEach(chip => {
            const nodeType = chip.dataset.type;
            
            // 鼠标悬停事件
            chip.addEventListener('mouseenter', () => {
                // 如果没有任何锁定的图例，则高亮显示当前悬停的图例对应的节点
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    chip.classList.add('active');
                    this.highlightNodesByType(nodeType);
                }
            });
            
            chip.addEventListener('mouseleave', () => {
                // 如果没有任何锁定的图例，则清除高亮
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    chip.classList.remove('active');
                    this.clearNodeHighlight();
                }
            });
            
            // 添加点击事件
            chip.addEventListener('click', () => {
                this.toggleLegendLock('nodeType', nodeType, chip);
            });
        });
        
        // 警告节点图例事件
        const warningChip = document.querySelector('.warning-chip');
        if (warningChip) {
            warningChip.addEventListener('mouseenter', () => {
                // 如果没有任何锁定的图例，则高亮显示警告节点
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    warningChip.classList.add('active');
                    this.highlightWarningNodes();
                }
            });
            
            warningChip.addEventListener('mouseleave', () => {
                // 如果没有任何锁定的图例，则清除高亮
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    warningChip.classList.remove('active');
                    this.clearNodeHighlight();
                }
            });
            
            // 添加点击事件
            warningChip.addEventListener('click', () => {
                this.toggleLegendLock('special', 'warning', warningChip);
            });
        }
        
        // 高成本节点图例事件
        const highCostChip = document.querySelector('.high-cost-chip');
        if (highCostChip) {
            highCostChip.addEventListener('mouseenter', () => {
                // 如果没有任何锁定的图例，则高亮显示高成本节点
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    highCostChip.classList.add('active');
                    this.highlightHighCostNodes();
                }
            });
            
            highCostChip.addEventListener('mouseleave', () => {
                // 如果没有任何锁定的图例，则清除高亮
                if (!this.lockedLegends.nodeType && !this.lockedLegends.special) {
                    highCostChip.classList.remove('active');
                    this.clearNodeHighlight();
                }
            });
            
            // 添加点击事件
            highCostChip.addEventListener('click', () => {
                this.toggleLegendLock('special', 'high-cost', highCostChip);
            });
        }
    }

    /**
     * 切换图例锁定状态
     * @param {string} lockType - 锁定类型：'nodeType' 或 'special'
     * @param {string} value - 锁定的值
     * @param {HTMLElement} chipElement - 图例元素
     */
    toggleLegendLock(lockType, value, chipElement) {
        // 清除所有图例的活跃状态
        document.querySelectorAll('.legend-chip').forEach(chip => {
            chip.classList.remove('active');
        });
        
        // 如果当前已经锁定了这个图例，则解锁
        if (this.lockedLegends[lockType] === value) {
            // 解锁
            this.lockedLegends.nodeType = null;
            this.lockedLegends.special = null;
            this.clearNodeHighlight();
        } else {
            // 锁定新的图例
            this.lockedLegends.nodeType = lockType === 'nodeType' ? value : null;
            this.lockedLegends.special = lockType === 'special' ? value : null;
            
            // 添加活跃状态
            chipElement.classList.add('active');
            
            // 高亮显示对应的节点
            if (lockType === 'nodeType') {
                this.highlightNodesByType(value);
            } else if (lockType === 'special') {
                if (value === 'warning') {
                    this.highlightWarningNodes();
                } else if (value === 'high-cost') {
                    this.highlightHighCostNodes();
                }
            }
        }
    }

    /**
     * 高亮指定类型的节点
     */
    highlightNodesByType(nodeType) {
        if (!this.graph) return;
        
        const nodes = this.graph.getNodes();
        nodes.forEach(node => {
            const model = node.getModel();
            
            if (model.originalData && model.originalData.node_type === nodeType) {
                this.graph.setItemState(node, 'selected', true);
            } else {
                // 安全的透明度设置
                const group = node.getContainer();
                const animate = group.animate;
                if (animate && typeof animate === 'function') {
                    try {
                        animate.call(group, { opacity: 0.3 }, 200);
                    } catch (e) {
                        group.attr('opacity', 0.3);
                    }
                } else {
                    group.attr('opacity', 0.3);
                }
            }
        });
        
        // 安全的边透明度设置
        const edges = this.graph.getEdges();
        edges.forEach(edge => {
            const group = edge.getContainer();
            const animate = group.animate;
            if (animate && typeof animate === 'function') {
                try {
                    animate.call(group, { opacity: 0.2 }, 200);
                } catch (e) {
                    group.attr('opacity', 0.2);
                }
            } else {
                group.attr('opacity', 0.2);
            }
        });
    }

    /**
     * 高亮警告节点
     */
    highlightWarningNodes() {
        if (!this.graph) return;
        
        const nodes = this.graph.getNodes();
        nodes.forEach(node => {
            const model = node.getModel();
            
            if (model.originalData && model.originalData.warnings && model.originalData.warnings.length > 0) {
                this.graph.setItemState(node, 'selected', true);
            } else {
                // 安全的透明度设置
                const group = node.getContainer();
                const animate = group.animate;
                if (animate && typeof animate === 'function') {
                    try {
                        animate.call(group, { opacity: 0.3 }, 200);
                    } catch (e) {
                        group.attr('opacity', 0.3);
                    }
                } else {
                    group.attr('opacity', 0.3);
                }
            }
        });
        
        // 安全的边透明度设置
        const edges = this.graph.getEdges();
        edges.forEach(edge => {
            const group = edge.getContainer();
            const animate = group.animate;
            if (animate && typeof animate === 'function') {
                try {
                    animate.call(group, { opacity: 0.2 }, 200);
                } catch (e) {
                    group.attr('opacity', 0.2);
                }
            } else {
                group.attr('opacity', 0.2);
            }
        });
    }

    /**
     * 高亮高成本节点
     */
    highlightHighCostNodes() {
        if (!this.graph) return;
        
        const nodes = this.graph.getNodes();
        nodes.forEach(node => {
            const model = node.getModel();
            
            if (model.originalData && model.originalData.performance_metrics && model.originalData.performance_metrics.cost > 100) {
                this.graph.setItemState(node, 'selected', true);
            } else {
                // 安全的透明度设置
                const group = node.getContainer();
                const animate = group.animate;
                if (animate && typeof animate === 'function') {
                    try {
                        animate.call(group, { opacity: 0.3 }, 200);
                    } catch (e) {
                        group.attr('opacity', 0.3);
                    }
                } else {
                    group.attr('opacity', 0.3);
                }
            }
        });
        
        // 安全的边透明度设置
        const edges = this.graph.getEdges();
        edges.forEach(edge => {
            const group = edge.getContainer();
            const animate = group.animate;
            if (animate && typeof animate === 'function') {
                try {
                    animate.call(group, { opacity: 0.2 }, 200);
                } catch (e) {
                    group.attr('opacity', 0.2);
                }
            } else {
                group.attr('opacity', 0.2);
            }
        });
    }

    /**
     * 清除节点高亮
     */
    clearNodeHighlight() {
        if (!this.graph) return;
        
        // 如果有锁定的图例，则不清除高亮
        if (this.lockedLegends.nodeType || this.lockedLegends.special) {
            return;
        }
        
        const nodes = this.graph.getNodes();
        nodes.forEach(node => {
            this.graph.setItemState(node, 'selected', false);
            const group = node.getContainer();
            
            // 安全的透明度恢复
            const animate = group.animate;
            if (animate && typeof animate === 'function') {
                try {
                    animate.call(group, { opacity: 1 }, 200);
                } catch (e) {
                    group.attr('opacity', 1);
                }
            } else {
                group.attr('opacity', 1);
            }
        });
        
        // 安全的边透明度恢复
        const edges = this.graph.getEdges();
        edges.forEach(edge => {
            const group = edge.getContainer();
            const animate = group.animate;
            if (animate && typeof animate === 'function') {
                try {
                    animate.call(group, { opacity: 0.8 }, 200);
                } catch (e) {
                    group.attr('opacity', 0.8);
                }
            } else {
                group.attr('opacity', 0.8);
            }
        });
    }

    /**
     * 添加节点进入动画
     */
    addEnterAnimation() {
        if (!this.graph) return;
        
        const nodes = this.graph.getNodes();
        nodes.forEach((node, index) => {
            const group = node.getContainer();
            
            // 使用最安全的G6动画方式
            try {
                // 先设置初始透明度
                group.attr('opacity', 0);
                
                // 延迟显示动画
                setTimeout(() => {
                    const animate = group.animate;
                    if (animate && typeof animate === 'function') {
                        // 使用最简单的动画参数格式
                        animate.call(group, { opacity: 1 }, 600);
                    } else {
                        // 兜底：直接设置
                        group.attr('opacity', 1);
                    }
                }, index * 100);
            } catch (e) {
                // 最终兜底：直接显示
                group.attr('opacity', 1);
            }
        });
        
        // 边的简化动画
        const edges = this.graph.getEdges();
        edges.forEach((edge, index) => {
            const group = edge.getContainer();
            
            try {
                group.attr('opacity', 0);
                
                setTimeout(() => {
                    const animate = group.animate;
                    if (animate && typeof animate === 'function') {
                        animate.call(group, { opacity: 0.8 }, 400);
                    } else {
                        group.attr('opacity', 0.8);
                    }
                }, (nodes.length + index) * 80 + 300);
            } catch (e) {
                group.attr('opacity', 0.8);
            }
        });
    }

    /**
     * 重置视图
     */
    resetView() {
        if (this.graph) {
            // 清除当前选中的节点
            this.clearNodeSelection();
            
            // 重置锁定的图例状态
            this.lockedLegends = {
                nodeType: null,
                special: null
            };
            
            // 清除所有图例的活跃状态
            document.querySelectorAll('.legend-chip').forEach(chip => {
                chip.classList.remove('active');
            });
            
            // 清除所有节点的高亮状态
            const nodes = this.graph.getNodes();
            nodes.forEach(node => {
                this.graph.setItemState(node, 'selected', false);
                const group = node.getContainer();
                if (group) {
                    group.attr('opacity', 1);
                }
            });
            
            // 恢复所有边的透明度
            const edges = this.graph.getEdges();
            edges.forEach(edge => {
                const group = edge.getContainer();
                if (group) {
                    group.attr('opacity', 0.8);
                }
            });
            
            // 使用G6兼容的方式进行视图重置
            try {
                // 尝试使用动画方式
                this.graph.fitView(20, { animate: true, duration: 500 });
            } catch (e) {
                // 兜底：直接适应视图
                this.graph.fitView();
            }
            this.currentZoom = 1;
        }
    }

    /**
     * 放大
     */
    zoomIn() {
        if (this.graph) {
            this.currentZoom = Math.min(this.currentZoom * 1.2, 3);
            // 使用G6兼容的缩放方式
            try {
                this.graph.zoomTo(this.currentZoom, undefined, true);
            } catch (e) {
                this.graph.zoom(this.currentZoom);
            }
        }
    }

    /**
     * 缩小
     */
    zoomOut() {
        if (this.graph) {
            this.currentZoom = Math.max(this.currentZoom / 1.2, 0.3);
            // 使用G6兼容的缩放方式
            try {
                this.graph.zoomTo(this.currentZoom, undefined, true);
            } catch (e) {
                this.graph.zoom(this.currentZoom);
            }
        }
    }

    /**
     * 导出PNG
     */
    exportPNG() {
        if (!this.graph) {
            alert('请先解析数据生成图表');
            return;
        }

        try {
            // 方法1: 使用G6 4.x的内置导出方法
            if (typeof this.graph.downloadFullImage === 'function') {
                console.log('使用G6内置导出方法');
                this.graph.downloadFullImage(`mysql-explain-${Date.now()}`, 'image/png');
                return;
            }
            console.log('G6内置导出方法不可用，尝试其他方法');

            // 方法2: 直接获取canvas元素
            const canvas = this.graph.get('canvas');
            if (canvas) {
                let canvasElement = null;
                
                // 尝试不同的获取canvas元素的方法
                if (canvas.get && typeof canvas.get === 'function') {
                    // 尝试 'el' 属性 (G6 4.x)
                    canvasElement = canvas.get('el');
                    
                    // 如果 'el' 不存在，尝试 'canvas' 属性
                    if (!canvasElement) {
                        canvasElement = canvas.get('canvas');
                    }
                }
                
                // 如果通过get方法获取失败，直接尝试访问属性
                if (!canvasElement && canvas.canvas) {
                    canvasElement = canvas.canvas;
                }
                
                // 如果canvas本身就是DOM元素
                if (!canvasElement && canvas.tagName === 'CANVAS') {
                    canvasElement = canvas;
                }

                if (canvasElement && canvasElement.toDataURL) {
                    console.log('使用方法2导出: 通过graph获取canvas');
                    const link = document.createElement('a');
                    link.download = `mysql-explain-${Date.now()}.png`;
                    link.href = canvasElement.toDataURL('image/png');
                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);
                    return;
                }
            }

            // 方法3: 查找页面中的canvas元素
            const graphContainer = document.getElementById(this.containerId);
            const canvasElements = graphContainer.querySelectorAll('canvas');
            
            if (canvasElements.length > 0) {
                console.log('使用方法3导出: 通过DOM查找canvas', canvasElements.length);
                const canvas = canvasElements[0]; // 使用第一个canvas
                const link = document.createElement('a');
                link.download = `mysql-explain-${Date.now()}.png`;
                link.href = canvas.toDataURL('image/png');
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                return;
            }

            throw new Error('无法找到可用的canvas元素');

        } catch (error) {
            console.error('导出PNG失败:', error);
            alert('导出图片失败，请稍后重试。错误信息：' + error.message);
        }
    }

    /**
     * 导出JSON
     */
    exportJSON() {
        if (this.data) {
            const dataStr = JSON.stringify(this.data, null, 2);
            const blob = new Blob([dataStr], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            
            const link = document.createElement('a');
            link.download = `mysql-explain-${Date.now()}.json`;
            link.href = url;
            link.click();
            
            URL.revokeObjectURL(url);
        }
    }

    /**
     * 处理窗口大小变化
     */
    handleResize() {
        if (this.graph) {
            const container = document.getElementById(this.containerId);
            const { clientWidth, clientHeight } = container;
            this.graph.changeSize(clientWidth, clientHeight);
        }
    }

    /**
     * 生成SQL示例
     */
    generateSqlExamples(node) {
        // 确保SQL示例生成器已初始化
        if (!this.sqlGenerator) {
            this.sqlGenerator = new SqlExampleGenerator();
        }
        
        return this.sqlGenerator.generateContextualExample(node);
    }

    /**
     * 生成优化建议SQL
     */
    generateOptimizationSQL(node) {
        if (!this.sqlGenerator) {
            this.sqlGenerator = new SqlExampleGenerator();
        }
        
        return this.sqlGenerator.generateOptimizationSQL(node);
    }

    /**
     * 转义HTML字符
     */
    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    /**
     * 简单的SQL语法高亮
     */
    highlightSQL(sql) {
        // 简单的语法高亮，将SQL关键字高亮显示
        const keywords = [
            'SELECT', 'FROM', 'WHERE', 'JOIN', 'INNER', 'LEFT', 'RIGHT', 'OUTER',
            'ON', 'GROUP BY', 'ORDER BY', 'HAVING', 'LIMIT', 'OFFSET',
            'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'ALTER', 'DROP',
            'INDEX', 'TABLE', 'DATABASE', 'EXPLAIN', 'ANALYZE', 'FORMAT',
            'AND', 'OR', 'NOT', 'IN', 'EXISTS', 'BETWEEN', 'LIKE',
            'COUNT', 'SUM', 'AVG', 'MAX', 'MIN', 'DISTINCT',
            'AS', 'ASC', 'DESC', 'NULL', 'IS', 'TRUE', 'FALSE'
        ];
        
        let highlighted = this.escapeHtml(sql);
        
        // 高亮SQL关键字
        keywords.forEach(keyword => {
            const regex = new RegExp(`\\b${keyword}\\b`, 'gi');
            highlighted = highlighted.replace(regex, `<span class="sql-keyword">${keyword.toUpperCase()}</span>`);
        });
        
        // 高亮字符串
        highlighted = highlighted.replace(/'([^']*)'/g, '<span class="sql-string">\'$1\'</span>');
        
        // 高亮数字
        highlighted = highlighted.replace(/\b(\d+(?:\.\d+)?)\b/g, '<span class="sql-number">$1</span>');
        
        // 高亮注释
        highlighted = highlighted.replace(/--([^\n]*)/g, '<span class="sql-comment">--$1</span>');
        
        return highlighted;
    }

    /**
     * 绑定SQL示例相关事件
     */
    bindSqlExampleEvents() {
        // 绑定展开/收起按钮
        const toggleBtn = document.getElementById('sqlExamplesToggle');
        if (toggleBtn) {
            toggleBtn.addEventListener('click', this.toggleSqlExamples.bind(this));
        }
        
        // 绑定复制按钮
        const copyBtns = document.querySelectorAll('.copy-sql-btn, .copy-explain-btn');
        copyBtns.forEach(btn => {
            btn.addEventListener('click', (e) => {
                const sql = e.target.getAttribute('data-sql');
                this.copyToClipboard(sql, e.target);
            });
        });
    }

    /**
     * 切换SQL示例展开/收起状态
     */
    toggleSqlExamples() {
        const content = document.getElementById('sqlExamplesContent');
        const toggleBtn = document.getElementById('sqlExamplesToggle');
        const icon = toggleBtn.querySelector('.toggle-icon');
        
        if (content.classList.contains('collapsed')) {
            // 展开
            content.classList.remove('collapsed');
            content.style.display = 'block';
            icon.textContent = '▼';
            toggleBtn.title = '收起SQL示例';
        } else {
            // 收起
            content.classList.add('collapsed');
            content.style.display = 'none';
            icon.textContent = '▶';
            toggleBtn.title = '展开SQL示例';
        }
    }

    /**
     * 复制文本到剪贴板
     */
    async copyToClipboard(text, button) {
        try {
            // 尝试使用现代的 Clipboard API
            if (navigator.clipboard && window.isSecureContext) {
                await navigator.clipboard.writeText(text);
                this.showCopySuccess(button);
            } else {
                // 降级方案：使用传统的 execCommand
                const textArea = document.createElement('textarea');
                textArea.value = text;
                textArea.style.position = 'fixed';
                textArea.style.opacity = '0';
                textArea.style.top = '-9999px';
                
                document.body.appendChild(textArea);
                textArea.select();
                textArea.setSelectionRange(0, 99999);
                
                const successful = document.execCommand('copy');
                document.body.removeChild(textArea);
                
                if (successful) {
                    this.showCopySuccess(button);
                } else {
                    throw new Error('Copy command failed');
                }
            }
        } catch (error) {
            console.error('复制失败:', error);
            this.showCopyError(button);
        }
    }

    /**
     * 显示复制成功提示
     */
    showCopySuccess(button) {
        const originalText = button.textContent;
        const originalTitle = button.title;
        
        button.textContent = '✅ 已复制';
        button.title = '复制成功';
        button.style.background = '#52c41a';
        button.style.color = 'white';
        
        setTimeout(() => {
            button.textContent = originalText;
            button.title = originalTitle;
            button.style.background = '';
            button.style.color = '';
        }, 2000);
    }

    /**
     * 显示复制失败提示
     */
    showCopyError(button) {
        const originalText = button.textContent;
        const originalTitle = button.title;
        
        button.textContent = '❌ 复制失败';
        button.title = '复制失败，请手动复制';
        button.style.background = '#ff4d4f';
        button.style.color = 'white';
        
        setTimeout(() => {
            button.textContent = originalText;
            button.title = originalTitle;
            button.style.background = '';
            button.style.color = '';
        }, 3000);
    }

    /**
     * 销毁图形
     */
    destroy() {
        if (this.graph) {
            this.graph.destroy();
            this.graph = null;
        }
    }
}

// 添加详情面板样式
const detailStyles = `
<style>
.detail-section {
    margin-bottom: 1.5rem;
}

.detail-section h4 {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.detail-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.5rem 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}

.detail-label {
    font-weight: 500;
    color: var(--text-secondary);
    flex: 0 0 100px;
}

.detail-value {
    color: var(--text-primary);
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
    font-size: 0.875rem;
    text-align: right;
    flex: 1;
}

.warning-item {
    background: #fff2f0;
    color: #a8071a;
    padding: 0.5rem;
    border-radius: 4px;
    margin-bottom: 0.5rem;
    font-size: 0.875rem;
}

.suggestion-item {
    background: #f6ffed;
    color: #389e0d;
    padding: 0.5rem;
    border-radius: 4px;
    margin-bottom: 0.5rem;
    font-size: 0.875rem;
}

/* SQL示例相关样式 */
.sql-examples-section {
    border-top: 2px solid var(--accent-color);
    padding-top: 1rem;
    margin-top: 1.5rem;
}

.sql-examples-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0.25rem;
    border-radius: 4px;
    transition: all 0.2s ease;
    color: var(--text-secondary);
    font-size: 0.875rem;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.sql-examples-toggle:hover {
    background: var(--hover-bg);
    color: var(--accent-color);
}

.toggle-icon {
    transition: transform 0.2s ease;
    font-size: 0.75rem;
}

.sql-examples-description {
    color: var(--text-secondary);
    font-size: 0.875rem;
    margin-bottom: 1rem;
    padding: 0.5rem;
    background: var(--surface-secondary);
    border-radius: 6px;
    border-left: 3px solid var(--accent-color);
}

.sql-examples-content {
    transition: all 0.3s ease;
}

.sql-examples-content.collapsed {
    display: none;
}

.sql-example-item {
    margin-bottom: 1.5rem;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    overflow: hidden;
    background: var(--surface-primary);
}

.sql-example-item.optimization-section {
    border-color: #fa8c16;
    background: linear-gradient(135deg, #fff7e6 0%, #fafafa 100%);
}

.sql-example-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.75rem 1rem;
    background: var(--surface-secondary);
    border-bottom: 1px solid var(--border-color);
}

.sql-example-header h5 {
    margin: 0;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-primary);
}

.sql-example-actions {
    display: flex;
    gap: 0.5rem;
}

.copy-sql-btn, .copy-explain-btn {
    padding: 0.375rem 0.75rem;
    border: 1px solid var(--border-color);
    background: var(--surface-primary);
    color: var(--text-primary);
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.75rem;
    transition: all 0.2s ease;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.copy-sql-btn:hover, .copy-explain-btn:hover {
    background: var(--accent-color);
    color: white;
    border-color: var(--accent-color);
    transform: translateY(-1px);
    box-shadow: 0 2px 8px rgba(24, 144, 255, 0.3);
}

.sql-code-block {
    padding: 1rem;
    background: #fafafa;
    border-radius: 0 0 8px 8px;
}

.sql-code-block pre {
    margin: 0;
    padding: 0;
    background: none;
    border: none;
    border-radius: 0;
    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', monospace;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--text-primary);
    overflow-x: auto;
}

.sql-code-block code {
    background: none;
    padding: 0;
    border: none;
    border-radius: 0;
    color: inherit;
}

/* SQL语法高亮 */
.sql-keyword {
    color: #0066cc;
    font-weight: 600;
}

.sql-string {
    color: #d73a49;
}

.sql-number {
    color: #005cc5;
}

.sql-comment {
    color: #6a737d;
    font-style: italic;
}

/* 暗色主题下的SQL样式调整 */
[data-theme="dark"] .sql-code-block {
    background: #1f1f1f;
}

[data-theme="dark"] .sql-keyword {
    color: #569cd6;
}

[data-theme="dark"] .sql-string {
    color: #ce9178;
}

[data-theme="dark"] .sql-number {
    color: #b5cea8;
}

[data-theme="dark"] .sql-comment {
    color: #6a9955;
}

/* 科技主题下的SQL样式调整 */
[data-theme="tech"] .sql-code-block {
    background: rgba(0, 255, 255, 0.05);
    border: 1px solid rgba(0, 255, 255, 0.2);
}

[data-theme="tech"] .sql-keyword {
    color: #00ffff;
}

[data-theme="tech"] .sql-string {
    color: #ff6b6b;
}

[data-theme="tech"] .sql-number {
    color: #4ecdc4;
}

[data-theme="tech"] .sql-comment {
    color: #95a5a6;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .sql-example-header {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
    }
    
    .sql-example-actions {
        width: 100%;
        justify-content: flex-end;
    }
    
    .copy-sql-btn, .copy-explain-btn {
        font-size: 0.7rem;
        padding: 0.25rem 0.5rem;
    }
}
</style>
`;

// 注入样式
document.head.insertAdjacentHTML('beforeend', detailStyles);

// 导出
window.ExplainVisualizer = ExplainVisualizer;